package com.itheima.supplier.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.cache.CacheService;
import com.itheima.enums.OrderStatusEnum;
import com.itheima.recharge.RechargeRequest;
import com.itheima.recharge.RechargeResponse;
import com.itheima.recharge.constants.SupplierConstants;
import com.itheima.recharge.entity.OrderTrade;
import com.itheima.recharge.mapper.OrderTradeMapper;
import com.itheima.response.Result;
import com.itheima.supplier.inf.SupplierService;
import com.itheima.supplier.inf.SupplierTask;
import com.itheima.supplier.properties.SupplierProperties;
import com.itheima.thirdparty.StatusCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.sound.midi.Soundbank;
import java.util.Set;

/**
 * Created by 传智播客*黑马程序员.
 */
@Service
@Slf4j
public class SupplierServiceImpl implements SupplierService {
    
    
    @Autowired
    private SupplierProperties supplierProperties;
    
    @Autowired
    private SupplierTask supplierTask;
    
    @Autowired
    private CacheService cacheService;
    
    @Override
    public void recharge(RechargeRequest rechargeRequest) {
        /**
         * - 编写对接逻辑分发方法：Result<RechargeResponse> doDispatchSupplier(RechargeRequest rechargeRequest)，根据供应商编号进行分发
         - 编写对接聚合的方法：Result<RechargeResponse> doPostJuhe(RechargeRequest rechargeRequest)
         - 编写对接极速的方法：Result<RechargeResponse> doPostJisu(RechargeRequest rechargeRequest)
         */
        //对重试次数进行限制
        if (rechargeRequest.getRepeat() > supplierProperties.getMaxrepeat()) {
            updateTrade(rechargeRequest.getOrderNo(), OrderStatusEnum.FAIL.getCode());
            return;
        }
        //检查供应商是否可用
        String supplys = checkSupply(rechargeRequest.getSupply());
        if (supplys == null) {
            updateTrade(rechargeRequest.getOrderNo(), OrderStatusEnum.FAIL.getCode());
            return;
        }
        rechargeRequest.setSupply(supplys);
        
        Result<RechargeResponse> responseResult = null;
        try {
            responseResult = doDispatchSupplier(rechargeRequest);
            System.out.println(responseResult);
        } catch (Exception e) {
            log.error("充值对接下单失败,{},{}",rechargeRequest,e.getMessage());
            rechargeRequest.setErrorCode(StatusCode.REMOTEERROR);
            supplierTask.addRetryTask(rechargeRequest);
            return;
        }
        if (responseResult == null) {
            log.error("充值对接对方无返回，{}",rechargeRequest);
            rechargeRequest.setErrorCode(StatusCode.ORDER_REQ_FAILED);
            supplierTask.addRetryTask(rechargeRequest);
            return;
        }
        
        if (responseResult.getCode() != StatusCode.OK) {
            //根据具体的错误码执行具体的业务
            if (responseResult.getCode() == StatusCode.ORDER_REQ_FAILED) {
                rechargeRequest.setErrorCode(StatusCode.ORDER_REQ_FAILED);
                supplierTask.addRetryTask(rechargeRequest);
                return;
            }else if (responseResult.getCode() == StatusCode.BALANCE_NOT_ENOUGH) {
                //余额不足，轮转到下一个供应商
                cacheService.sAdd(SupplierConstants.exclude_supplier,rechargeRequest.getSupply());
                String supply = nextSupply();
                if (supply == null) {
                    //没有可以用的供应商了
                    updateTrade(rechargeRequest.getOrderNo(),OrderStatusEnum.FAIL.getCode());
                    return;
                }

                rechargeRequest.setSupply(supply);
                rechargeRequest.setRepeat(0);
                rechargeRequest.setErrorCode(StatusCode.BALANCE_NOT_ENOUGH);
                supplierTask.addRetryTask(rechargeRequest);
                return;
                
            }
            
        }
        
        
        //对接成功了
        //充值对接成功
        log.info("下单成功,等待充值处理回调！");
        //特别注意此时订单状态还不能修改为充值成功-----供应商回调之后才能修改为成功
        updateTrade(rechargeRequest.getOrderNo(),OrderStatusEnum.UNAFFIRM.getCode());//充值处理中等待确认
        
        
        
        
        return;
        
        
      /*  rechargeRequest.setErrorCode(StatusCode.ORDER_REQ_FAILED);
        supplierTask.addRetryTask(rechargeRequest);*/
    }

    private String checkSupply(String supply) {
        Set<String> excludes = cacheService.setMembers(SupplierConstants.exclude_supplier);
        if (excludes.contains(supply)) {
            return nextSupply();
        }
        return supply;
    }

    private String nextSupply() {
        Set<String> excludes = cacheService.setMembers(SupplierConstants.exclude_supplier);
        Set<String> supplies = supplierProperties.getApis().keySet();
        for (String supply : supplies) {
            if (!excludes.contains(supply)) {
                return supply;
            }
        }
        return null;
    }

    private Result<RechargeResponse> doDispatchSupplier(RechargeRequest rechargeRequest) {
        //根据供应商编号获取接口请求地址
        String url = supplierProperties.getApis().get(rechargeRequest.getSupply());
        rechargeRequest.setRechargeUrl(url);
        
        //根据供应商编号分发不同的对接逻辑
        if (SupplierConstants.juheapi.equals(rechargeRequest.getSupply())) {
            return doPostJuhe(rechargeRequest);
        }else if (SupplierConstants.jisuapi.equals(rechargeRequest.getSupply())) {
            return doPostJisu(rechargeRequest);
        }
        return null;
    }

    private Result<RechargeResponse> doPostJisu(RechargeRequest rechargeRequest) {
        log.info("doPostJisu,{}",rechargeRequest);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        //设置表单参数
        MultiValueMap<String, String> map= new LinkedMultiValueMap<String, String>();
        map.add("mobile",rechargeRequest.getMobile());
        map.add("amount",rechargeRequest.getPamt()+"");
        map.add("outorderNo", rechargeRequest.getOrderNo());
        map.add("repeat", ""+rechargeRequest.getRepeat());

        //模拟请求失败
        map.add("req_status", ""+ StatusCode.OK);
        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<MultiValueMap<String, String>>(map, headers);
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(rechargeRequest.getRechargeUrl(), requestEntity , String.class);
        //转换成统一对象
        Result<RechargeResponse> result= JSON.parseObject(responseEntity.getBody(), new TypeReference<Result<RechargeResponse>>(){});
        return result;
    }

    @Autowired
    private RestTemplate restTemplate;

    private Result<RechargeResponse> doPostJuhe(RechargeRequest rechargeRequest) {
        //聚合要求传递的是json格式的数据
        //创建并设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        //创建请求实体
        HttpEntity httpEntity = new HttpEntity(JSON.toJSONString(rechargeRequest),headers);
        //发送请求
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(rechargeRequest.getRechargeUrl(), httpEntity, String.class);
        //获得结果
    /*String body = responseEntity.getBody();// Result<RechargeResponse>
        Result result = JSON.parseObject(body, Result.class);//因为泛型的问题可能会导致出现问题
        System.out.println(body);*/
        Result<RechargeResponse> result = JSON.parseObject(responseEntity.getBody(), new TypeReference<Result<RechargeResponse>>(){});
        return result;
    }


    @Autowired
    private OrderTradeMapper orderTradeMapper;
    private void updateTrade(String  orderNo, int orderStatus) {
        //修改订单状态
        QueryWrapper<OrderTrade> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_no", orderNo);
        OrderTrade orderTrade = orderTradeMapper.selectOne(queryWrapper);
        if(orderTrade!=null) {
            orderTrade.setOrderStatus(orderStatus);
            orderTradeMapper.updateById(orderTrade);
        }
    }
}
